package com.silence.gmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.silence.gmall.product.assembler.BaseAttrInfoFactory;
import com.silence.gmall.product.assembler.BaseAttrValueFactory;
import com.silence.gmall.product.domain.entity.BaseAttrInfo;
import com.silence.gmall.product.domain.entity.BaseAttrValue;
import com.silence.gmall.product.domain.repository.BaseAttrInfoRepository;
import com.silence.gmall.product.domain.repository.BaseAttrValueRepository;
import com.silence.gmall.product.dto.BaseAttrInfoDto;
import com.silence.gmall.product.dto.BaseAttrValueDto;
import com.silence.gmall.product.service.BaseAttrInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @Author silence
 * @Description 针对表【base_attr_info(属性表)】的数据库操作Service实现
 * @Date 2025-08-17 16:28:16
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BaseAttrInfoServiceImpl implements BaseAttrInfoService {

    /**
     * BaseAttrInfoRepository 的注入
     */
    private final BaseAttrInfoRepository baseAttrInfoRepository;

    /**
     * BaseAttrValueRepository 的注入
     */
    private final BaseAttrValueRepository baseAttrValueRepository;

    /**
     * BaseAttrInfoFactory 的注入
     */
    private final BaseAttrInfoFactory baseAttrInfoFactory;

    /**
     * BaseAttrValueFactory 的注入
     */
    private final BaseAttrValueFactory baseAttrValueFactory;

    /**
     * 根据平台属性ID获取平台属性对象数据
     *
     * @param attrId 平台属性ID
     * @return 平台属性对象数据
     */
    @Override
    public List<BaseAttrValueDto> getAttrValueList(String attrId) {
        return baseAttrValueFactory.baseAttrValue2BaseAttrValueDto(baseAttrValueRepository.list(new LambdaQueryWrapper<BaseAttrValue>()
                .eq(BaseAttrValue::getAttrId, attrId)));
    }

    /**
     * 添加修改平台属性
     *
     * @param reqVo 添加修改平台属性请求对象
     */
    @Override
    public void saveOrUpdateAttrInfo(BaseAttrInfoDto reqVo) {
        if (Objects.isNull(reqVo.getId())) {
            saveAttrInfo(reqVo);
        } else {
            updateAttrInfo(reqVo);
        }
    }

    /**
     * 保存平台属性
     *
     * @param reqVo 请求参数
     */
    private void saveAttrInfo(BaseAttrInfoDto reqVo) {
        // 保存平台属性
        BaseAttrInfo baseAttrInfo = baseAttrInfoFactory.baseAttrInfoDto2BaseAttrInfo(reqVo);
        baseAttrInfoRepository.save(baseAttrInfo);

        if (CollectionUtils.isEmpty(reqVo.getAttrValueList())) {
            return;
        }

        // 保存属性值
        List<BaseAttrValue> baseAttrValueList = baseAttrValueFactory.baseAttrValueDtoList2BaseAttrValueListWithContext(reqVo.getAttrValueList(), baseAttrInfo.getId());
        baseAttrValueRepository.saveBatch(baseAttrValueList, baseAttrValueList.size());
    }

    /**
     * 修改平台属性
     *
     * @param reqVo 请求参数
     */
    private void updateAttrInfo(BaseAttrInfoDto reqVo) {
        // 修改平台属性
        BaseAttrInfo baseAttrInfo = baseAttrInfoFactory.baseAttrInfoDto2BaseAttrInfo(reqVo);
        baseAttrInfoRepository.updateById(baseAttrInfo);

        // 处理属性值的增删改
        handleAttrValues(reqVo.getAttrValueList(), baseAttrInfo.getId());
    }

    /**
     * 处理属性值的增删改操作
     *
     * @param attrValueList 属性值列表
     * @param attrId        属性ID
     */
    private void handleAttrValues(List<BaseAttrValueDto> attrValueList, Long attrId) {
        // 如果集合为空，删除所有属性值
        if (CollectionUtils.isEmpty(attrValueList)) {
            baseAttrValueRepository.remove(new LambdaQueryWrapper<BaseAttrValue>()
                    .eq(BaseAttrValue::getAttrId, attrId));
            return;
        }

        // 使用Stream API一次性分离数据，提高代码简洁性
        Map<Boolean, List<BaseAttrValueDto>> partitionedData = attrValueList.stream()
                .collect(Collectors.partitioningBy(dto -> Objects.nonNull(dto.getId())));

        List<BaseAttrValueDto> toUpdate = partitionedData.get(true);
        List<BaseAttrValueDto> toInsert = partitionedData.get(false);

        // 批量删除不存在的属性值
        deleteObsoleteAttrValues(attrId, toUpdate);

        // 并行处理批量新增和更新
        CompletableFuture<Void> insertFuture = CompletableFuture.runAsync(() ->
                batchInsertAttrValues(toInsert, attrId));

        CompletableFuture<Void> updateFuture = CompletableFuture.runAsync(() ->
                batchUpdateAttrValues(toUpdate));

        // 等待所有操作完成
        CompletableFuture.allOf(insertFuture, updateFuture).join();
    }

    /**
     * 批量删除过期的属性值
     *
     * @param attrId   属性ID
     * @param toUpdate 需要更新的数据列表
     */
    private void deleteObsoleteAttrValues(Long attrId, List<BaseAttrValueDto> toUpdate) {
        if (CollectionUtils.isEmpty(toUpdate)) {
            // 如果没有要保留的记录，删除所有该属性下的属性值
            baseAttrValueRepository.remove(new LambdaQueryWrapper<BaseAttrValue>()
                    .eq(BaseAttrValue::getAttrId, attrId));
            return;
        }

        Set<String> existingIds = toUpdate.stream()
                .map(BaseAttrValueDto::getId)
                .collect(Collectors.toSet());

        baseAttrValueRepository.remove(new LambdaQueryWrapper<BaseAttrValue>()
                .eq(BaseAttrValue::getAttrId, attrId)
                .notIn(BaseAttrValue::getId, existingIds));
    }

    /**
     * 批量新增属性值
     *
     * @param toInsert 待新增的数据
     * @param attrId   属性ID
     */
    private void batchInsertAttrValues(List<BaseAttrValueDto> toInsert, Long attrId) {
        if (CollectionUtils.isEmpty(toInsert)) {
            return;
        }

        List<BaseAttrValue> insertList = baseAttrValueFactory
                .baseAttrValueDtoList2BaseAttrValueListWithContext(toInsert, attrId);
        baseAttrValueRepository.saveBatch(insertList, insertList.size());
    }

    /**
     * 批量更新属性值
     *
     * @param toUpdate 待更新的数据
     */
    private void batchUpdateAttrValues(List<BaseAttrValueDto> toUpdate) {
        if (CollectionUtils.isEmpty(toUpdate)) {
            return;
        }

        List<BaseAttrValue> updateList = baseAttrValueFactory
                .baseAttrValueDtoList2BaseAttrValueList(toUpdate);
        baseAttrValueRepository.updateBatchById(updateList, updateList.size());
    }
}